import mongoose, { Schema, Model, Document, HookNextFunction } from 'mongoose';
import validator from 'validator';
import jwt from 'jsonwebtoken';
import { UserPayload } from '../typings/jwt';
import bcrypt from 'bcryptjs';

export interface IUserDocument extends Document {
    username: string,
    password: string,
    avator: string,
    email: string,
    generateToken:() => string,
    _doc: IUserDocument
}

const UserSchema: Schema<IUserDocument> = new Schema({
    username: {
        type: String,
        required: [true, '用户名不能为空'],
        minlength: [6, '最小长度不能小于6位'],
        maxlength: [12, '最大长度不能大于12位']
    },
    password: String,
    avator: String,
    email: {
        type: String,
        validate: {
            validator: validator.isEmail
        },
        trim: true  // 字符串前后去空格
    }
}, {
    timestamps: true,
    toJSON: {
        transform: function(_doc:any, result:any){
            result.id = result._id;
            delete result._id;
            delete result.__v;
            delete result.password;
            delete result.createdAt;
            delete result.updatedAt;
            return result;
        }
    }
});  // 使用时间戳 会自动添加两个字段 createAt updateAt



UserSchema.methods.generateToken! = function(this:IUserDocument): string{
    let payload: UserPayload = ({ id: this._id });
    return jwt.sign(payload, process.env.JWT_SECRET_KEY!, { expiresIn: '1h' });
}
UserSchema.pre<IUserDocument>('save', async function(next: HookNextFunction){
    if(!this.isModified('password')){
        return next();
    }
    try {
        this.password = await bcrypt.hash(this.password, 10);
    } catch (error) {
        next(error);
    }
});

UserSchema.static('login', async function(this:any, username:string, password:string):Promise<IUserDocument|null>{
    let user: IUserDocument | null = await this.model('User').findOne({ username });
    if(user){
        const matched = await bcrypt.compare(password, user.password);
        if(matched){
            return user;
        }else{
            return null;
        }
    }
    return user;
});

interface IUserModel<T extends Document> extends Model<T>{
    login: (username: string, password: string) => IUserDocument | null;
}

export const User: IUserModel<IUserDocument> = mongoose.model<IUserDocument, IUserModel<IUserDocument>>('User', UserSchema);